home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / zupath.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  15.9 KB  |  678 lines

  1. /* Copyright (C) 1990, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: zupath.c,v 1.2 2000/09/19 19:00:55 lpd Exp $ */
  20. /* Operators related to user paths */
  21. #include "ghost.h"
  22. #include "oper.h"
  23. #include "oparc.h"
  24. #include "idict.h"
  25. #include "dstack.h"
  26. #include "igstate.h"
  27. #include "iname.h"
  28. #include "iutil.h"
  29. #include "store.h"
  30. #include "stream.h"
  31. #include "ibnum.h"
  32. #include "gsmatrix.h"
  33. #include "gsstate.h"
  34. #include "gscoord.h"
  35. #include "gspaint.h"
  36. #include "gxfixed.h"
  37. #include "gxdevice.h"
  38. #include "gspath.h"
  39. #include "gzpath.h"        /* for saving path */
  40. #include "gzstate.h"        /* for accessing path */
  41.  
  42. /* Imported data */
  43. extern const gx_device gs_hit_device;
  44. extern const int gs_hit_detected;
  45.  
  46. /* Forward references */
  47. private int upath_append(P2(os_ptr, i_ctx_t *));
  48. private int upath_stroke(P2(i_ctx_t *, gs_matrix *));
  49.  
  50. /* ---------------- Insideness testing ---------------- */
  51.  
  52. /* Forward references */
  53. private int in_test(P2(i_ctx_t *, int (*)(P1(gs_state *))));
  54. private int in_path(P3(os_ptr, i_ctx_t *, gx_device *));
  55. private int in_path_result(P3(i_ctx_t *, int, int));
  56. private int in_utest(P2(i_ctx_t *, int (*)(P1(gs_state *))));
  57. private int in_upath(P2(i_ctx_t *, gx_device *));
  58. private int in_upath_result(P3(i_ctx_t *, int, int));
  59.  
  60. /* <x> <y> ineofill <bool> */
  61. /* <userpath> ineofill <bool> */
  62. private int
  63. zineofill(i_ctx_t *i_ctx_p)
  64. {
  65.     return in_test(i_ctx_p, gs_eofill);
  66. }
  67.  
  68. /* <x> <y> infill <bool> */
  69. /* <userpath> infill <bool> */
  70. private int
  71. zinfill(i_ctx_t *i_ctx_p)
  72. {
  73.     return in_test(i_ctx_p, gs_fill);
  74. }
  75.  
  76. /* <x> <y> instroke <bool> */
  77. /* <userpath> instroke <bool> */
  78. private int
  79. zinstroke(i_ctx_t *i_ctx_p)
  80. {
  81.     return in_test(i_ctx_p, gs_stroke);
  82. }
  83.  
  84. /* <x> <y> <userpath> inueofill <bool> */
  85. /* <userpath1> <userpath2> inueofill <bool> */
  86. private int
  87. zinueofill(i_ctx_t *i_ctx_p)
  88. {
  89.     return in_utest(i_ctx_p, gs_eofill);
  90. }
  91.  
  92. /* <x> <y> <userpath> inufill <bool> */
  93. /* <userpath1> <userpath2> inufill <bool> */
  94. private int
  95. zinufill(i_ctx_t *i_ctx_p)
  96. {
  97.     return in_utest(i_ctx_p, gs_fill);
  98. }
  99.  
  100. /* <x> <y> <userpath> inustroke <bool> */
  101. /* <x> <y> <userpath> <matrix> inustroke <bool> */
  102. /* <userpath1> <userpath2> inustroke <bool> */
  103. /* <userpath1> <userpath2> <matrix> inustroke <bool> */
  104. private int
  105. zinustroke(i_ctx_t *i_ctx_p)
  106. {    /* This is different because of the optional matrix operand. */
  107.     os_ptr op = osp;
  108.     int code = gs_gsave(igs);
  109.     int spop, npop;
  110.     gs_matrix mat;
  111.     gx_device hdev;
  112.  
  113.     if (code < 0)
  114.     return code;
  115.     if ((spop = upath_stroke(i_ctx_p, &mat)) < 0) {
  116.     gs_grestore(igs);
  117.     return spop;
  118.     }
  119.     if ((npop = in_path(op - spop, i_ctx_p, &hdev)) < 0) {
  120.     gs_grestore(igs);
  121.     return npop;
  122.     }
  123.     if (npop > 1)        /* matrix was supplied */
  124.     code = gs_concat(igs, &mat);
  125.     if (code >= 0)
  126.     code = gs_stroke(igs);
  127.     return in_upath_result(i_ctx_p, npop + spop, code);
  128. }
  129.  
  130. /* ------ Internal routines ------ */
  131.  
  132. /* Do the work of the non-user-path insideness operators. */
  133. private int
  134. in_test(i_ctx_t *i_ctx_p, int (*paintproc)(P1(gs_state *)))
  135. {
  136.     os_ptr op = osp;
  137.     gx_device hdev;
  138.     int npop = in_path(op, i_ctx_p, &hdev);
  139.     int code;
  140.  
  141.     if (npop < 0)
  142.     return npop;
  143.     code = (*paintproc)(igs);
  144.     return in_path_result(i_ctx_p, npop, code);
  145. }
  146.  
  147. /* Set up a clipping path and device for insideness testing. */
  148. private int
  149. in_path(os_ptr oppath, i_ctx_t *i_ctx_p, gx_device * phdev)
  150. {
  151.     int code = gs_gsave(igs);
  152.     int npop;
  153.     double uxy[2];
  154.  
  155.     if (code < 0)
  156.     return code;
  157.     code = num_params(oppath, 2, uxy);
  158.     if (code >= 0) {        /* Aperture is a single pixel. */
  159.     gs_point dxy;
  160.     gs_fixed_rect fr;
  161.  
  162.     gs_transform(igs, uxy[0], uxy[1], &dxy);
  163.     fr.p.x = fixed_floor(float2fixed(dxy.x));
  164.     fr.p.y = fixed_floor(float2fixed(dxy.y));
  165.     fr.q.x = fr.p.x + fixed_1;
  166.     fr.q.y = fr.p.y + fixed_1;
  167.     code = gx_clip_to_rectangle(igs, &fr);
  168.     npop = 2;
  169.     } else {            /* Aperture is a user path. */
  170.     /* We have to set the clipping path without disturbing */
  171.     /* the current path. */
  172.     gx_path *ipath = igs->path;
  173.     gx_path save;
  174.  
  175.     gx_path_init_local(&save, imemory);
  176.     gx_path_assign_preserve(&save, ipath);
  177.     gs_newpath(igs);
  178.     code = upath_append(oppath, i_ctx_p);
  179.     if (code >= 0)
  180.         code = gx_clip_to_path(igs);
  181.     gx_path_assign_free(igs->path, &save);
  182.     npop = 1;
  183.     }
  184.     if (code < 0) {
  185.     gs_grestore(igs);
  186.     return code;
  187.     }
  188.     /* Install the hit detection device. */
  189.     gx_set_device_color_1(igs);
  190.     gx_device_init((gx_device *) phdev, (const gx_device *)&gs_hit_device,
  191.            NULL, true);
  192.     phdev->width = phdev->height = max_int;
  193.     gx_device_fill_in_procs(phdev);
  194.     gx_set_device_only(igs, phdev);
  195.     return npop;
  196. }
  197.  
  198. /* Finish an insideness test. */
  199. private int
  200. in_path_result(i_ctx_t *i_ctx_p, int npop, int code)
  201. {
  202.     os_ptr op = osp;
  203.     bool result;
  204.  
  205.     gs_grestore(igs);        /* matches gsave in in_path */
  206.     if (code == gs_hit_detected)
  207.     result = true;
  208.     else if (code == 0)        /* completed painting without a hit */
  209.     result = false;
  210.     else            /* error */
  211.     return code;
  212.     npop--;
  213.     pop(npop);
  214.     op -= npop;
  215.     make_bool(op, result);
  216.     return 0;
  217.  
  218. }
  219.  
  220. /* Do the work of the user-path insideness operators. */
  221. private int
  222. in_utest(i_ctx_t *i_ctx_p, int (*paintproc)(P1(gs_state *)))
  223. {
  224.     gx_device hdev;
  225.     int npop = in_upath(i_ctx_p, &hdev);
  226.     int code;
  227.  
  228.     if (npop < 0)
  229.     return npop;
  230.     code = (*paintproc)(igs);
  231.     return in_upath_result(i_ctx_p, npop, code);
  232. }
  233.  
  234. /* Set up a clipping path and device for insideness testing */
  235. /* with a user path. */
  236. private int
  237. in_upath(i_ctx_t *i_ctx_p, gx_device * phdev)
  238. {
  239.     os_ptr op = osp;
  240.     int code = gs_gsave(igs);
  241.     int npop;
  242.  
  243.     if (code < 0)
  244.     return code;
  245.     if ((code = upath_append(op, i_ctx_p)) < 0 ||
  246.     (npop = in_path(op - 1, i_ctx_p, phdev)) < 0
  247.     ) {
  248.     gs_grestore(igs);
  249.     return code;
  250.     }
  251.     return npop + 1;
  252. }
  253.  
  254. /* Finish an insideness test with a user path. */
  255. private int
  256. in_upath_result(i_ctx_t *i_ctx_p, int npop, int code)
  257. {
  258.     gs_grestore(igs);        /* matches gsave in in_upath */
  259.     return in_path_result(i_ctx_p, npop, code);
  260. }
  261.  
  262. /* ---------------- User paths ---------------- */
  263.  
  264. /* User path operator codes */
  265. typedef enum {
  266.     upath_op_setbbox = 0,
  267.     upath_op_moveto = 1,
  268.     upath_op_rmoveto = 2,
  269.     upath_op_lineto = 3,
  270.     upath_op_rlineto = 4,
  271.     upath_op_curveto = 5,
  272.     upath_op_rcurveto = 6,
  273.     upath_op_arc = 7,
  274.     upath_op_arcn = 8,
  275.     upath_op_arct = 9,
  276.     upath_op_closepath = 10,
  277.     upath_op_ucache = 11
  278. } upath_op;
  279.  
  280. #define UPATH_MAX_OP 11
  281. #define UPATH_REPEAT 32
  282. static const byte up_nargs[UPATH_MAX_OP + 1] = {
  283.     4, 2, 2, 2, 2, 6, 6, 5, 5, 5, 0, 0
  284. };
  285.  
  286. /* Declare operator procedures not declared in opextern.h. */
  287. int zsetbbox(P1(i_ctx_t *));
  288. private int zucache(P1(i_ctx_t *));
  289.  
  290. #undef zp
  291. static const op_proc_t up_ops[UPATH_MAX_OP + 1] = {
  292.     zsetbbox, zmoveto, zrmoveto, zlineto, zrlineto,
  293.     zcurveto, zrcurveto, zarc, zarcn, zarct,
  294.     zclosepath, zucache
  295. };
  296.  
  297. /* - ucache - */
  298. private int
  299. zucache(i_ctx_t *i_ctx_p)
  300. {
  301.     /* A no-op for now. */
  302.     return 0;
  303. }
  304.  
  305. /* <userpath> uappend - */
  306. private int
  307. zuappend(i_ctx_t *i_ctx_p)
  308. {
  309.     os_ptr op = osp;
  310.     int code = gs_gsave(igs);
  311.  
  312.     if (code < 0)
  313.     return code;
  314.     if ((code = upath_append(op, i_ctx_p)) >= 0)
  315.     code = gs_upmergepath(igs);
  316.     gs_grestore(igs);
  317.     if (code < 0)
  318.     return code;
  319.     pop(1);
  320.     return 0;
  321. }
  322.  
  323. /* <userpath> ueofill - */
  324. private int
  325. zueofill(i_ctx_t *i_ctx_p)
  326. {
  327.     os_ptr op = osp;
  328.     int code = gs_gsave(igs);
  329.  
  330.     if (code < 0)
  331.     return code;
  332.     if ((code = upath_append(op, i_ctx_p)) >= 0)
  333.     code = gs_eofill(igs);
  334.     gs_grestore(igs);
  335.     if (code < 0)
  336.     return code;
  337.     pop(1);
  338.     return 0;
  339. }
  340.  
  341. /* <userpath> ufill - */
  342. private int
  343. zufill(i_ctx_t *i_ctx_p)
  344. {
  345.     os_ptr op = osp;
  346.     int code = gs_gsave(igs);
  347.  
  348.     if (code < 0)
  349.     return code;
  350.     if ((code = upath_append(op, i_ctx_p)) >= 0)
  351.     code = gs_fill(igs);
  352.     gs_grestore(igs);
  353.     if (code < 0)
  354.     return code;
  355.     pop(1);
  356.     return 0;
  357. }
  358.  
  359. /* <userpath> ustroke - */
  360. /* <userpath> <matrix> ustroke - */
  361. private int
  362. zustroke(i_ctx_t *i_ctx_p)
  363. {
  364.     int code = gs_gsave(igs);
  365.     int npop;
  366.  
  367.     if (code < 0)
  368.     return code;
  369.     if ((code = npop = upath_stroke(i_ctx_p, NULL)) >= 0)
  370.     code = gs_stroke(igs);
  371.     gs_grestore(igs);
  372.     if (code < 0)
  373.     return code;
  374.     pop(npop);
  375.     return 0;
  376. }
  377.  
  378. /* <userpath> ustrokepath - */
  379. /* <userpath> <matrix> ustrokepath - */
  380. private int
  381. zustrokepath(i_ctx_t *i_ctx_p)
  382. {
  383.     gx_path save;
  384.     int code, npop;
  385.  
  386.     /* Save and reset the path. */
  387.     gx_path_init_local(&save, imemory);
  388.     gx_path_assign_preserve(&save, igs->path);
  389.     if ((code = npop = upath_stroke(i_ctx_p, NULL)) < 0 ||
  390.     (code = gs_strokepath(igs)) < 0
  391.     ) {
  392.     gx_path_assign_free(igs->path, &save);
  393.     return code;
  394.     }
  395.     gx_path_free(&save, "ustrokepath");
  396.     pop(npop);
  397.     return 0;
  398. }
  399.  
  400. /* <with_ucache> upath <userpath> */
  401. /* We do all the work in a procedure that is also used to construct */
  402. /* the UnpaintedPath user path for ImageType 2 images. */
  403. int make_upath(P5(i_ctx_t *i_ctx_p, ref *rupath, gs_state *pgs, gx_path *ppath,
  404.           bool with_ucache));
  405. private int
  406. zupath(i_ctx_t *i_ctx_p)
  407. {
  408.     os_ptr op = osp;
  409.  
  410.     check_type(*op, t_boolean);
  411.     return make_upath(i_ctx_p, op, igs, igs->path, op->value.boolval);
  412. }
  413. int
  414. make_upath(i_ctx_t *i_ctx_p, ref *rupath, gs_state *pgs, gx_path *ppath,
  415.        bool with_ucache)
  416. {
  417.     int size = (with_ucache ? 6 : 5);
  418.     gs_path_enum penum;
  419.     int op;
  420.     ref *next;
  421.     int code;
  422.  
  423.     /* Compute the size of the user path array. */
  424.     {
  425.     gs_fixed_point pts[3];
  426.  
  427.     gx_path_enum_init(&penum, ppath);
  428.     while ((op = gx_path_enum_next(&penum, pts)) != 0) {
  429.         switch (op) {
  430.         case gs_pe_moveto:
  431.         case gs_pe_lineto:
  432.             size += 3;
  433.             continue;
  434.         case gs_pe_curveto:
  435.             size += 7;
  436.             continue;
  437.         case gs_pe_closepath:
  438.             size += 1;
  439.             continue;
  440.         default:
  441.             return_error(e_unregistered);
  442.         }
  443.     }
  444.     }
  445.     code = ialloc_ref_array(rupath, a_all | a_executable, size,
  446.                 "make_upath");
  447.     if (code < 0)
  448.     return code;
  449.     /* Construct the path. */
  450.     next = rupath->value.refs;
  451.     if (with_ucache) {
  452.     if ((code = name_enter_string("ucache", next)) < 0)
  453.         return code;
  454.     r_set_attrs(next, a_executable | l_new);
  455.     ++next;
  456.     } {
  457.     gs_rect bbox;
  458.  
  459.     gs_upathbbox(pgs, &bbox, true);
  460.     make_real_new(next, bbox.p.x);
  461.     make_real_new(next + 1, bbox.p.y);
  462.     make_real_new(next + 2, bbox.q.x);
  463.     make_real_new(next + 3, bbox.q.y);
  464.     next += 4;
  465.     if ((code = name_enter_string("setbbox", next)) < 0)
  466.         return code;
  467.     r_set_attrs(next, a_executable | l_new);
  468.     ++next;
  469.     }
  470.     {
  471.     gs_point pts[3];
  472.  
  473.     /* Patch the path in the gstate to set up the enumerator. */
  474.     gx_path *save_path = pgs->path;
  475.  
  476.     pgs->path = ppath;
  477.     gs_path_enum_copy_init(&penum, pgs, false);
  478.     pgs->path = save_path;
  479.     while ((op = gs_path_enum_next(&penum, pts)) != 0) {
  480.         const char *opstr;
  481.  
  482.         switch (op) {
  483.         case gs_pe_moveto:
  484.             opstr = "moveto";
  485.             goto ml;
  486.         case gs_pe_lineto:
  487.             opstr = "lineto";
  488.           ml:make_real_new(next, pts[0].x);
  489.             make_real_new(next + 1, pts[0].y);
  490.             next += 2;
  491.             break;
  492.         case gs_pe_curveto:
  493.             opstr = "curveto";
  494.             make_real_new(next, pts[0].x);
  495.             make_real_new(next + 1, pts[0].y);
  496.             make_real_new(next + 2, pts[1].x);
  497.             make_real_new(next + 3, pts[1].y);
  498.             make_real_new(next + 4, pts[2].x);
  499.             make_real_new(next + 5, pts[2].y);
  500.             next += 6;
  501.             break;
  502.         case gs_pe_closepath:
  503.             opstr = "closepath";
  504.             break;
  505.         default:
  506.             return_error(e_unregistered);
  507.         }
  508.         if ((code = name_enter_string(opstr, next)) < 0)
  509.         return code;
  510.         r_set_attrs(next, a_executable);
  511.         ++next;
  512.     }
  513.     }
  514.     return 0;
  515. }
  516.  
  517. /* ------ Internal routines ------ */
  518.  
  519. /* Append a user path to the current path. */
  520. private int
  521. upath_append(os_ptr oppath, i_ctx_t *i_ctx_p)
  522. {
  523.     check_read(*oppath);
  524.     gs_newpath(igs);
  525. /****** ROUND tx AND ty ******/
  526.     if (r_has_type(oppath, t_array) && r_size(oppath) == 2 &&
  527.     r_has_type(oppath->value.refs + 1, t_string)
  528.     ) {            /* 1st element is operators, 2nd is operands */
  529.     const ref *operands = oppath->value.refs;
  530.     int code, format;
  531.     int repcount = 1;
  532.     const byte *opp;
  533.     uint ocount, i = 0;
  534.  
  535.     code = num_array_format(operands);
  536.     if (code < 0)
  537.         return code;
  538.     format = code;
  539.     opp = oppath->value.refs[1].value.bytes;
  540.     ocount = r_size(&oppath->value.refs[1]);
  541.     while (ocount--) {
  542.         byte opx = *opp++;
  543.  
  544.         if (opx > UPATH_REPEAT)
  545.         repcount = opx - UPATH_REPEAT;
  546.         else if (opx > UPATH_MAX_OP)
  547.         return_error(e_rangecheck);
  548.         else {        /* operator */
  549.         do {
  550.             os_ptr op = osp;
  551.             byte opargs = up_nargs[opx];
  552.  
  553.             while (opargs--) {
  554.             push(1);
  555.             code = num_array_get(operands, format, i++, op);
  556.             switch (code) {
  557.                 case t_integer:
  558.                 r_set_type_attrs(op, t_integer, 0);
  559.                 break;
  560.                 case t_real:
  561.                 r_set_type_attrs(op, t_real, 0);
  562.                 break;
  563.                 default:
  564.                 return_error(e_typecheck);
  565.             }
  566.             }
  567.             code = (*up_ops[opx])(i_ctx_p);
  568.             if (code < 0)
  569.             return code;
  570.         }
  571.         while (--repcount);
  572.         repcount = 1;
  573.         }
  574.     }
  575.     } else if (r_is_array(oppath)) {    /* Ordinary executable array. */
  576.     const ref *arp = oppath;
  577.     uint ocount = r_size(oppath);
  578.     long index = 0;
  579.     int argcount = 0;
  580.     op_proc_t oproc;
  581.     int opx, code;
  582.  
  583.     for (; index < ocount; index++) {
  584.         ref rup;
  585.         ref *defp;
  586.         os_ptr op = osp;
  587.  
  588.         array_get(arp, index, &rup);
  589.         switch (r_type(&rup)) {
  590.         case t_integer:
  591.         case t_real:
  592.             argcount++;
  593.             push(1);
  594.             *op = rup;
  595.             break;
  596.         case t_name:
  597.             if (!r_has_attr(&rup, a_executable))
  598.             return_error(e_typecheck);
  599.             if (dict_find(systemdict, &rup, &defp) <= 0)
  600.             return_error(e_undefined);
  601.             if (r_btype(defp) != t_operator)
  602.             return_error(e_typecheck);
  603.             goto xop;
  604.         case t_operator:
  605.             defp = &rup;
  606.           xop:if (!r_has_attr(defp, a_executable))
  607.             return_error(e_typecheck);
  608.             oproc = real_opproc(defp);
  609.             for (opx = 0; opx <= UPATH_MAX_OP; opx++)
  610.             if (oproc == up_ops[opx])
  611.                 break;
  612.             if (opx > UPATH_MAX_OP || argcount != up_nargs[opx])
  613.             return_error(e_typecheck);
  614.             code = (*oproc)(i_ctx_p);
  615.             if (code < 0)
  616.             return code;
  617.             argcount = 0;
  618.             break;
  619.         default:
  620.             return_error(e_typecheck);
  621.         }
  622.     }
  623.     if (argcount)
  624.         return_error(e_typecheck);    /* leftover args */
  625.     } else
  626.     return_error(e_typecheck);
  627.     return 0;
  628. }
  629.  
  630. /* Append a user path to the current path, and then apply or return */
  631. /* a transformation if one is supplied. */
  632. private int
  633. upath_stroke(i_ctx_t *i_ctx_p, gs_matrix *pmat)
  634. {
  635.     os_ptr op = osp;
  636.     int code, npop;
  637.     gs_matrix mat;
  638.  
  639.     if ((code = read_matrix(op, &mat)) >= 0) {
  640.     if ((code = upath_append(op - 1, i_ctx_p)) >= 0) {
  641.         if (pmat)
  642.         *pmat = mat;
  643.         else
  644.         code = gs_concat(igs, &mat);
  645.     }
  646.     npop = 2;
  647.     } else {
  648.     if ((code = upath_append(op, i_ctx_p)) >= 0)
  649.         if (pmat)
  650.         gs_make_identity(pmat);
  651.     npop = 1;
  652.     }
  653.     return (code < 0 ? code : npop);
  654. }
  655.  
  656. /* ---------------- Initialization procedure ---------------- */
  657.  
  658. const op_def zupath_l2_op_defs[] =
  659. {
  660.     op_def_begin_level2(),
  661.         /* Insideness testing */
  662.     {"1ineofill", zineofill},
  663.     {"1infill", zinfill},
  664.     {"1instroke", zinstroke},
  665.     {"2inueofill", zinueofill},
  666.     {"2inufill", zinufill},
  667.     {"2inustroke", zinustroke},
  668.         /* User paths */
  669.     {"1uappend", zuappend},
  670.     {"0ucache", zucache},
  671.     {"1ueofill", zueofill},
  672.     {"1ufill", zufill},
  673.     {"1upath", zupath},
  674.     {"1ustroke", zustroke},
  675.     {"1ustrokepath", zustrokepath},
  676.     op_def_end(0)
  677. };
  678.